package com.zsc.oj.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;

import com.zsc.oj.common.ErrorCode;
import com.zsc.oj.exception.BusinessException;
import com.zsc.oj.mapper.FriendsMapper;
import com.zsc.oj.model.dto.friend.FriendApplyRequest;
import com.zsc.oj.model.dto.friend.SendMessageRequest;
import com.zsc.oj.model.entity.Friends;
import com.zsc.oj.model.entity.Message;
import com.zsc.oj.model.entity.User;
import com.zsc.oj.model.vo.FriendsVO;
import com.zsc.oj.model.vo.MessageVO;
import com.zsc.oj.service.FriendsService;
import com.zsc.oj.service.MessageService;
import com.zsc.oj.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.zsc.oj.utils.JsonToStringUtils.stringJsonListToSet;


/**
 *
 */
@Service
public class FriendsServiceImpl extends ServiceImpl<FriendsMapper, Friends>
    implements FriendsService {

    @Resource
    private RedissonClient redissonClient;
    @Resource
    private UserService userService;
    @Resource
    private MessageService messageService;

    /**
     * 申请添加好友
     * @param friendApplyRequest
     * @param loginUser
     * @return
     */
    @Override
    public boolean applyAddUser(FriendApplyRequest friendApplyRequest, User loginUser) {

        //备注字符不能大于102个字符
        String remark = friendApplyRequest.getRemark();
        if(StringUtils.isNotBlank(remark) && remark.length() > 102){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"备注不能大于102个字符");
        }

        //不能添加自己为好友
        Long receiveId = friendApplyRequest.getReceiveId();
        if(receiveId == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long userId = loginUser.getId();
        if(userId.equals(receiveId)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"不能添加自己为好友");
        }

        //todo 用户肯能会疯狂点击申请，导致重复的申请，需要用锁
        RLock lock = redissonClient.getLock("partner_match:apply_friend");
        try {
            while(true){
                if(lock.tryLock(0,30000L, TimeUnit.MILLISECONDS)){
                    //不能重复申请
                    //申请表中，若查询出申请人和接收者与当前对应的记录有两条以上就是重复申请
                    LambdaQueryWrapper<Friends> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                    lambdaQueryWrapper.eq(Friends::getFromId,userId);
                    lambdaQueryWrapper.eq(Friends::getReceiveId,receiveId);
                    long count = this.count(lambdaQueryWrapper);
                    if(count > 0){
                        throw new BusinessException(ErrorCode.PARAMS_ERROR,"不能重复申请");
                    }

                    Friends friends = new Friends();
                    friends.setFromId(userId);
                    friends.setReceiveId(receiveId);
                    friends.setCreateTime(new Date());
                    friends.setRemark(remark);

                    if(StringUtils.isBlank(remark)){
                        friends.setRemark("我是：" + loginUser.getUserName());
                    }
                    boolean result = this.save(friends);

                    return result;
                }
            }
        }catch (InterruptedException e){
            log.error("apply error");
            return false;
        }finally {
            if (lock.isHeldByCurrentThread()) {
                System.out.println("unLock: " + Thread.currentThread().getId());
                lock.unlock();
            }
        }

    }

    /**
     * 展示申请列表
     * @param loginUser
     * @return
     */
    @Override
    public List<FriendsVO> showFriendsApplyList(User loginUser) {
        long userId = loginUser.getId();
        QueryWrapper<Friends> friendsQueryWrapper = new QueryWrapper<>();
        friendsQueryWrapper.eq("receiveId",userId);
        friendsQueryWrapper.eq("status",0);
        List<Friends> friendsList = this.list(friendsQueryWrapper);
        if(friendsList.isEmpty()){
            return new ArrayList<>();
        }

        //查询出对应的备注信息
        List<String> remarkList = friendsList.stream().map(Friends::getRemark).collect(Collectors.toList());
        //查询出申请人的id列表
        List<Long> fromIdList = friendsList.stream().map(Friends::getFromId).collect(Collectors.toList());
        //查询出申请列表的状态
        List<Integer> statusList = friendsList.stream().map(Friends::getStatus).collect(Collectors.toList());

        //查询出申请人的所有信息
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.in("id",fromIdList);
        List<User> fromUserList = userService.list(userQueryWrapper);

        //信息脱敏
        List<FriendsVO> friendsVOList = new ArrayList<>();
        for (User user : fromUserList) {
            FriendsVO friendsVO = new FriendsVO();
            BeanUtils.copyProperties(user,friendsVO);
            friendsVOList.add(friendsVO);
        }

        //将备注信息放入队列中，方便后续进行脱敏
        Queue<String> queue = new LinkedList<>();
        for (String s : remarkList) {
            queue.add(s);
        }

        //将列表状态放入队列，方便后续脱敏
        Queue<Integer> statusQueue = new LinkedList<>();
        for (Integer status : statusList) {
            statusQueue.add(status);
        }

        for (FriendsVO friendsVO : friendsVOList) {
            friendsVO.setRemark(queue.poll());
            friendsVO.setStatus(statusQueue.poll());
        }

        return friendsVOList;
    }

    /**
     * 同意添加好友
     * @param fromId
     * @param loginUser
     * @return
     */
    @Override
    public boolean agreeApply(Long fromId, User loginUser) {
        //loginUser为接收者
        long userId = loginUser.getId();

        LambdaQueryWrapper<Friends> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Friends::getFromId,fromId);
        lambdaQueryWrapper.eq(Friends::getReceiveId,userId);
        List<Friends> friendsList = this.list(lambdaQueryWrapper);

        if(friendsList.isEmpty()){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"无申请");
        }

        if(friendsList.size() > 1){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"操作有误，请重试");
        }

        //boolean类型原子性操作
        AtomicBoolean flag = new AtomicBoolean(false);

        //遍历拿到每一条申请记录
        friendsList.forEach(friends -> {
            //查询出申请人和接收者中对应User表中的所有信息。
            User fromUser = userService.getById(fromId);
            User receiveUser = userService.getById(loginUser.getId());

            //取出申请人和接收者对应的 friendsIds，并将调用工具类将其转换成set集合
            Set<Long> fromFriendsIds = stringJsonListToSet(fromUser.getFriendIds());
            Set<Long> receiveFriendsIds = stringJsonListToSet(receiveUser.getFriendIds());

            //在申请人的set集合中加入接收者的id，在接收者的set集合中加入申请人的id
            fromFriendsIds.add(receiveUser.getId());
            receiveFriendsIds.add(fromUser.getId());

            //然后分别将这两个set转成json格式，并设置在其第一步的实体类中
            Gson gson = new Gson();
            String jsonFromUserUserIds = gson.toJson(fromFriendsIds);
            String jsonReceiveFriendsIds = gson.toJson(receiveFriendsIds);

            fromUser.setFriendIds(jsonFromUserUserIds);
            receiveUser.setFriendIds(jsonReceiveFriendsIds);

            //将friends的状态给位1（已同意）
            friends.setStatus(1);

            //使用update进行更新，但需要注意：要考虑原子性（要么都做要么都不做），这里使用一个 `AtomicBoolean`类
            flag.set(userService.updateById(fromUser) && userService.updateById(receiveUser) && this.updateById(friends));
        });
        return flag.get();
    }

    /**
     * 拒绝添加为好友
     * @param fromId
     * @param loginUser
     * @return
     */
    @Override
    public boolean disagreeApply(Long fromId, User loginUser) {
        long userId = loginUser.getId();
        //boolean类型原子性操作
        AtomicBoolean flag = new AtomicBoolean(false);
        LambdaUpdateWrapper<Friends> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(Friends::getFromId,fromId);
        lambdaUpdateWrapper.eq(Friends::getReceiveId,userId);
        lambdaUpdateWrapper.set(Friends::getIsDelete,1);
        flag.set(this.update(lambdaUpdateWrapper));
        return flag.get();
    }

    /**
     * 展示我发出的申请
     * @param loginUser
     * @return
     */
    @Override
    public List<FriendsVO> showMySendList(User loginUser) {
        long userId = loginUser.getId();
        QueryWrapper<Friends> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("fromId",userId);
        queryWrapper.eq("status",0);
        List<Friends> friendsList = this.list(queryWrapper);
        if(friendsList.isEmpty()){
            return new ArrayList<>();
        }
        List<Integer> statusList = friendsList.stream().map(Friends::getStatus).collect(Collectors.toList());
        List<Long> receiveIdList = friendsList.stream().map(Friends::getReceiveId).collect(Collectors.toList());

        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.in("id",receiveIdList);
        List<User> userList = userService.list(userQueryWrapper);

        Queue<Integer> queue = new LinkedList<>();
        for (Integer status : statusList) {
            queue.add(status);
        }

        List<FriendsVO> friendsVOList = new ArrayList<>();
        for (User user : userList) {
            FriendsVO friendsVO = new FriendsVO();
            BeanUtils.copyProperties(user,friendsVO);
            Integer status = queue.poll();
            friendsVO.setStatus(status);
            friendsVOList.add(friendsVO);
        }

        return friendsVOList;
    }

    /**
     * 删除好友
     * @param id
     * @param loginUser
     * @return
     */
    @Override
    public boolean deleteFriend(Long id, User loginUser) {
        long userId = loginUser.getId();
        //分两大步：1、当用户删除好友，好友删除当前用户
        AtomicBoolean flag = new AtomicBoolean(false);
        //1、修改当前用户的好友列表
        //查询出当前登录用户的好友列表
        String friendsIds = loginUser.getFriendIds();
        //将好友列表转成set集合
        Set<Long> set = stringJsonListToSet(friendsIds);
        //删除好友
        set.remove(id);
        Gson gson = new Gson();

        //将集合转成json存入用户表
        String json = gson.toJson(set);
        LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(User::getId,userId);
        lambdaUpdateWrapper.set(User::getFriendIds,json);

        //2、好友删除当前用户
        User user = userService.getById(id);
        String userFriendsIds = user.getFriendIds();
        Set<Long> userSet = stringJsonListToSet(userFriendsIds);
        userSet.remove(userId);

        String gsonJson = gson.toJson(userSet);
        LambdaUpdateWrapper<User> userLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        userLambdaUpdateWrapper.eq(User::getId,id);
        userLambdaUpdateWrapper.set(User::getFriendIds,gsonJson);

        //更新操作
        flag.set(userService.update(lambdaUpdateWrapper) && userService.update(userLambdaUpdateWrapper));

        return flag.get();
    }

    /**
     * 消息发送
     * @param sendMessageRequest
     * @return
     */
    @Override
    public boolean sendMessage(SendMessageRequest sendMessageRequest) {
        String content = sendMessageRequest.getMessage();
        Long fromId = sendMessageRequest.getFromId();
        Long receiveId = sendMessageRequest.getReceiveId();

        if(StringUtils.isBlank(content)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"消息不能为空");
        }
        if(fromId == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"发送者id为空");
        }
        if(receiveId == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"接收者id为空");
        }


        Message message = new Message();
        message.setContent(content);
        message.setStatus(0);
        message.setFromId(fromId);
        message.setReceiveId(receiveId);
        boolean result = messageService.save(message);

        return result;
    }

    /**
     * 获取信息
     * @param id
     * @return
     */
    @Override
    public List<MessageVO> getMyMessage(Long id) {
        if(id == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<Message> messageQueryWrapper = new QueryWrapper<>();
        messageQueryWrapper.eq("receiveId",id);
        //[{id=1,fromId=1,received=2,content="测试",status=0},{id=2,fromId=1,received=3,content="测试2",status=0}]
        List<Message> messageList = messageService.list(messageQueryWrapper);

        List<MessageVO> messageVOList = new ArrayList<>();
        for (Message message : messageList) {
            MessageVO messageVO = new MessageVO();
            BeanUtils.copyProperties(message,messageVO);
            messageVOList.add(messageVO);
        }

        for (MessageVO messageVO : messageVOList) {
            Long fromId = messageVO.getFromId();
            User user = userService.getById(fromId);
            messageVO.setUser(user);
        }

        return messageVOList;
    }

}




